package com.easytake.emotioncat.interceptor;

import com.easytake.emotioncat.annotation.RequireToken;
import com.easytake.emotioncat.exception.AuthorException;
import com.easytake.emotioncat.util.WxCacheUtil;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.apache.tomcat.util.http.MimeHeaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestWrapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 登录拦截器
 */
@Component
public class LoginInterceptor implements HandlerInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Object classz = handlerMethod.getBean();
        boolean classRequire = classz.getClass().isAnnotationPresent(RequireToken.class);

        Method method = handlerMethod.getMethod();
        boolean methodRequire = method.isAnnotationPresent(RequireToken.class);

        if (!classRequire && !methodRequire) {
            return true;
        }

        String token = request.getHeader("token");

        if (Objects.isNull(token)) {
            throw new AuthorException("请求头中缺少认证信息");
        }

        String openId = WxCacheUtil.getOpenId(token);
        if (Objects.isNull(openId)) {
            throw new AuthorException("认证信息非法,请重新登录");
        }
        HashMap<String, String> headerMap = new HashMap<>();
        headerMap.put("wx_uid", openId);
        addHeader(request, headerMap);
        return true;
    }

    /**
     * 更改请求头
     *
     * @param request
     * @param headerMap
     */
    private void addHeader(HttpServletRequest request, HashMap<String, String> headerMap) {
        try {
            if (headerMap == null || headerMap.isEmpty()) {
                return;
            }
            Field reqeustField = ReflectionUtils.findField(ServletRequestWrapper.class, "request", ServletRequest.class);
            reqeustField.setAccessible(true);
            RequestFacade innerRequest = (RequestFacade) reqeustField.get(request);

            Field connectorField = ReflectionUtils.findField(RequestFacade.class, "request", Request.class);
            connectorField.setAccessible(true);
            Request connectorRequest = (Request) connectorField.get(innerRequest);

            Field coyoteField = ReflectionUtils.findField(Request.class, "coyoteRequest", org.apache.coyote.Request.class);
            coyoteField.setAccessible(true);
            org.apache.coyote.Request coyoteRequest = (org.apache.coyote.Request) coyoteField.get(connectorRequest);

            Field mimeHeadersField = ReflectionUtils.findField(org.apache.coyote.Request.class, "headers", MimeHeaders.class);
            mimeHeadersField.setAccessible(true);
            MimeHeaders mimeHeaders = (MimeHeaders) mimeHeadersField.get(coyoteRequest);
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                mimeHeaders.removeHeader(entry.getKey());
                mimeHeaders.addValue(entry.getKey()).setString(entry.getValue());
            }
        } catch (Exception e) {
            logger.error("更改请求头失败", e.getMessage());
        }
    }

}
